package com.zdpx.wordgen.controller;

import com.zdpx.wordgen.domain.HeatData;
import com.zdpx.wordgen.domain.Postion;
import com.zdpx.wordgen.domain.posRange;
import org.geotools.coverage.grid.GridCoordinates2D;
import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.coverage.grid.GridCoverageFactory;
import org.geotools.coverage.grid.GridGeometry2D;
import org.geotools.coverage.grid.io.AbstractGridFormat;
import org.geotools.coverage.grid.io.GridCoverage2DReader;
import org.geotools.coverage.grid.io.GridFormatFinder;
import org.geotools.data.collection.ListFeatureCollection;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.factory.CommonFactoryFinder;
import org.geotools.feature.DefaultFeatureCollection;
import org.geotools.feature.simple.SimpleFeatureBuilder;
import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
import org.geotools.gce.geotiff.GeoTiffFormat;
import org.geotools.gce.geotiff.GeoTiffReader;
import org.geotools.gce.geotiff.GeoTiffWriter;
import org.geotools.geometry.Envelope2D;
import org.geotools.geometry.jts.JTSFactoryFinder;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.map.GridCoverageLayer;
import org.geotools.map.GridReaderLayer;
import org.geotools.map.Layer;
import org.geotools.process.vector.HeatmapProcess;
import org.geotools.referencing.CRS;
import org.geotools.referencing.crs.DefaultGeographicCRS;
import org.geotools.styling.*;
import org.geotools.swing.JMapFrame;
import org.geotools.util.factory.Hints;
import org.locationtech.jts.geom.*;
import org.locationtech.jts.geom.Point;
import org.locationtech.jts.geom.Polygon;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.filter.FilterFactory;
import org.opengis.geometry.DirectPosition;
import org.opengis.geometry.MismatchedDimensionException;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;

import javax.imageio.ImageIO;
import javax.media.jai.PlanarImage;
import javax.xml.crypto.dsig.TransformException;
import java.awt.*;
import java.awt.image.*;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Date;
import java.util.List;

import static java.util.Base64.getEncoder;


public class TiffGen {
   // private static final String[] GEO_TYPE = new String[]{"Geometry", "Point", "LineString", "Polygon", "MultiPoint", "MultiLineString", "MultiPolygon", "GeometryCollection"};
    private PrecisionModel precisionModel = new PrecisionModel(PrecisionModel.FLOATING);
    private GeometryFactory geometryFactory = new GeometryFactory(precisionModel,4326);

    //创建GeometryFactory工厂
    SimpleFeatureCollection collection =null;

    SimpleFeatureCollection featureCollection = null;

    private StyleFactory sf = CommonFactoryFinder.getStyleFactory();
    private FilterFactory ff = CommonFactoryFinder.getFilterFactory();

    private JMapFrame frame;
    private GridCoverage2DReader reader;

    File file=new File("test.tiff");

    public BufferedImage mapColorsWithLUT(BufferedImage srcImage) {
        byte[] redMap = new byte[256]; // 创建一个红色映射表，例如将红色映射为蓝色等价物
        for (int i = 0; i < 256; i++) {
            redMap[i] = (byte) i; // 示例：直接复制红色值到蓝色通道，不做修改，仅为示例说明如何使用LUT
        }
        ByteLookupTable redLUT = new ByteLookupTable(0, redMap); // 0 表示红色通道的查找表
        LookupOp lookupOp = new LookupOp(redLUT, null); // 创建 LookupOp 对象，这里使用 null 作为第二个参数表示不对其他颜色通道进行操作
        return lookupOp.filter(srcImage, null); // 应用 LookupOp 到源图像上，并返回结果图像
    }


    public static BufferedImage TransparencyToZero(int width, int height) {

        BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics2D gd = bi.createGraphics();
        bi = gd.getDeviceConfiguration().createCompatibleImage(width, height, Transparency.TRANSLUCENT);
        gd = bi.createGraphics();

        return bi;
    }

    //数值颜色映射处理
    private static int[] getColorMsg(double data){
        double[] gradient = new double[]{0.05,0.1,0.15, 0.2, 0.25, 0.30, 0.35, 0.40, 0.45, 0.50, 0.55, 0.60, 0.65, 0.70,0.75,0.80,0.85,0.9,0.95,1};
        int[][] gradientColor = new int[][]{
                {1, 120, 146, 25},
                {1, 160, 246, 255},
                {0, 236, 236, 255},
                {0, 216, 0, 255},
                {1, 144, 0, 255},
                {255, 255, 0, 255},
                {231, 192, 0, 255},
                {255, 144, 0, 255},
                {255, 0, 0, 255},
                {214, 0, 0, 255},
                {192, 0, 0, 255},
                {180, 0, 0, 255},
                {200, 0, 240, 255},
                {240, 144, 180, 255},
                {180, 120, 240, 255},
                {170, 110, 240, 255},
                {160, 100, 240, 255},
                {150, 120, 240, 255},
                {180, 100, 100, 255},
                {200, 15, 15, 255}
        };
        int[] colorMsg = new int[4];
        for(int i=0;i<gradient.length-1;i++){
            if(data<=gradient[i]){
                colorMsg = gradientColor[i];
                break;
            }
            if(data==gradient[i+1]){
                colorMsg = gradientColor[i+1];
                break;
            }
            if(data>gradient[i]&&data<gradient[i+1]){
                colorMsg[0] = Double.valueOf((gradientColor[i+1][0]-gradientColor[i][0])/(gradient[i+1]-gradient[i])*(data-gradient[i])+gradientColor[i][0]).intValue();
                colorMsg[1] = Double.valueOf((gradientColor[i+1][1]-gradientColor[i][1])/(gradient[i+1]-gradient[i])*(data-gradient[i])+gradientColor[i][1]).intValue();
                colorMsg[2] = Double.valueOf((gradientColor[i+1][2]-gradientColor[i][2])/(gradient[i+1]-gradient[i])*(data-gradient[i])+gradientColor[i][2]).intValue();
                colorMsg[3] = gradientColor[i+1][3];
                break;
            }
            if(i+1==gradient.length-1){
                colorMsg = gradientColor[i+1];
            }
        }
        return colorMsg;
    }
    public String Base64Encode(String fn) throws IOException {
//        ByteArrayOutputStream baos=null;
//        String suffix=fn.substring(fn.lastIndexOf(".")+1);
//        File imgFile=new File(fn);
//        BufferedImage bufferedImage= ImageIO.read(imgFile);
//        baos=new ByteArrayOutputStream();
//        ImageIO.write(bufferedImage,suffix,baos);
//        byte[] bytes=baos.toByteArray();

        return Base64.getEncoder().encodeToString(fn.getBytes());
    }

    public String buildGeo(HeatData heatData) throws IOException, FactoryException {
        posRange range= heatData.getRange();
        //构建参考坐标系统及范围
        ReferencedEnvelope box = new ReferencedEnvelope(range.getMinLon(), range.getMaxLon(), range.getMinLat(), range.getMaxLat(), CRS.decode("EPSG:4326"));
        double lonPerPix=Math.abs(range.getMaxLon()-range.getMinLon())/heatData.getWidth();
        double latPerPix=Math.abs(range.getMaxLat()-range.getMinLat())/heatData.getHeight();
        SimpleFeatureTypeBuilder typeBuilder = new SimpleFeatureTypeBuilder();
        typeBuilder.setName("Flag");  // type 字段
        typeBuilder.add("name", String.class);
        typeBuilder.setCRS(CRS.decode("EPSG:4326"));
        typeBuilder.add("location", Point.class);
        SimpleFeatureType featureType = typeBuilder.buildFeatureType();   //构建特征类型

        GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory();  //几何形状工厂
        Coordinate[] coords =
                new Coordinate[]{new Coordinate(121.1034, 24.0235), new Coordinate(121.1034, 24.489),
                        new Coordinate(121.400, 24.4830), new Coordinate(121.4234, 24.029), new Coordinate(121.0234, 24.3035)};

        SimpleFeatureBuilder builder = new SimpleFeatureBuilder(featureType);
        double[][] parray = {{121.10195, 24.0200}, {121.10195, 24.035},
                {121.224, 24.123}, {121.320, 24.35}
        };
        List<Postion> PointData = heatData.getPosValData();
        List<SimpleFeature> features = new ArrayList<>();
        //构造热力图图片
        BufferedImage outPutImg=new BufferedImage(heatData.getWidth(),heatData.getHeight(),BufferedImage.TYPE_4BYTE_ABGR);
        //单色数据图
        BufferedImage sampeImg=new BufferedImage(heatData.getWidth(),heatData.getHeight(),BufferedImage.TYPE_BYTE_GRAY);

        Raster sampleData = null;
        if (heatData.isHasValue()) {

            SimpleFeatureCollection collection = new ListFeatureCollection(featureType, features);
            HeatmapProcess heatmapProcess = new HeatmapProcess();
            GridCoverage2D coverage2D = heatmapProcess.execute(collection, 1, null, 1, box, heatData.getWidth(), heatData.getHeight(), null);
            PlanarImage renderedImage = (PlanarImage) coverage2D.getRenderedImage();
            WritableRaster wrRaster = renderedImage.getAsBufferedImage().getRaster();
            for(Postion pos:PointData)
            {
                double lon=pos.getLon();
                double lat=pos.getLat();
                double val=pos.getVal();
                int i=(int)((lon-range.getMinLon())/lonPerPix);
                int j=(int)((range.getMaxLat()-lat)/latPerPix);
                wrRaster.setSample(i,j,0,val);
            }
            sampleData=wrRaster;
        } else
        {
            for (Postion pos:PointData) {
                builder.reset();
                builder.add("china");
                builder.add(createPoint(pos.getLon(), pos.getLat()));
                SimpleFeature feature = builder.buildFeature("auto");
                features.add(feature);
            }

            // 创建要素集合
            SimpleFeatureCollection collection = new ListFeatureCollection(featureType, features);
            HeatmapProcess heatmapProcess = new HeatmapProcess();
            GridCoverage2D coverage2D = heatmapProcess.execute(collection, heatData.getFactor(), null, 1, box, heatData.getWidth(), heatData.getHeight(), null);
            PlanarImage renderedImage = (PlanarImage) coverage2D.getRenderedImage();
            sampleData=renderedImage.getData();
        }
        for(int i=0;i<heatData.getHeight();i++){
            for(int j=0;j<heatData.getWidth();j++){
                double[] pixel = sampleData.getPixel(j, i, new double[1]);
                int rgba;
                if(Double.isNaN(pixel[0])||pixel[0]<0.05){
                    rgba = new Color(0,0,0,0).getRGB();
                }else {
                    int[] colorMsg = getColorMsg(pixel[0]);
                    rgba = new Color(colorMsg[0],colorMsg[1],colorMsg[2],colorMsg[3]).getRGB();
                }
                outPutImg.setRGB(i,j,rgba);
            }
        }
        GridCoverageFactory factory = new GridCoverageFactory();
        GridCoverage2D coveragetif = factory.create("example", outPutImg, box); // 使用默认CRS和范围，也可以自定义CRS和范围
        String fn="newTest.tiff";
        long timeStamp =System.currentTimeMillis();
        SimpleDateFormat sdf=new SimpleDateFormat("yyyyMMDDHHmmss");
        fn=sdf.format(new Date(timeStamp));
        fn=fn+".tiff";
        File outfile=new File(fn);
        GeoTiffWriter writer=new GeoTiffWriter(outfile, null);
        writer.write(coveragetif,null);
        writer.dispose();
        return Base64Encode(fn);
    }


    private void getGridCoverage2DReader() {
        String imageUrl = "test.tiff";
        File file = new File(imageUrl);
        AbstractGridFormat format = GridFormatFinder.findFormat(file);
        // this is a bit hacky but does make more geotiffs work
        Hints hints = new Hints();
        if (format instanceof GeoTiffFormat) {
            hints = new Hints(Hints.FORCE_LONGITUDE_FIRST_AXIS_ORDER, Boolean.TRUE);
        }
        reader = format.getReader(file, hints);
    }


    public void readTiff(String fileId) throws IOException, FactoryException, org.opengis.referencing.operation.TransformException {
        byte[] fn=Base64.getDecoder().decode(fileId);
        File file = new File(new String(fn));

        GeoTiffReader reader = new GeoTiffReader(file);
        GridCoverage2D coverage = reader.read(null);
        GeoTiffWriter writer=new GeoTiffWriter(file);

        //Style rasterRgbStyle = StyleUtil.createRGBStyle(reader);
        //Layer layer = new GridCoverageLayer(coverage, rasterRgbStyle, "测试06");

        //设置坐标系
        //CoordinateReferenceSystem targetCRS = CRS.decode("EPSG:4326");
        // 将 GridCoverage 进行重采样转换为另一个 CRS
        //coverage = (GridCoverage2D) Operations.DEFAULT.resample(coverage, targetCRS);

        // 获取图像范围
        PlanarImage image = (PlanarImage)coverage.getRenderedImage();

        System.out.println("通道数:"+image.getBounds());
        // 获取栅格数据集的几何属性
        GridGeometry2D geometry = coverage.getGridGeometry();


        Envelope2D envelope2D = coverage.getEnvelope2D();
        System.out.println("tongdaoshu:"+coverage.getNumSampleDimensions());
        double width = image.getWidth();
        System.out.println("图片宽:" + width);
        double height = image.getHeight();
        System.out.println("图片高:" + height);
        //获取边界值
        double minX = envelope2D.getBounds().getMinX();
        double minY = envelope2D.getBounds().getMinY();
        double maxX = envelope2D.getBounds().getMaxX();
        double maxY = envelope2D.getBounds().getMaxY();
        double pixelWidth = (maxX - minX) / width;
        double pixelHeight = (maxY - minY) / height;
        DirectPosition upperCorner = envelope2D.getUpperCorner();
        DirectPosition lowerCorner = envelope2D.getLowerCorner();
        System.out.println("minX:" + minX);
        System.out.println("maxX:" + maxX);
        System.out.println("minY:" + minY);
        System.out.println("maxY:" + maxY);
        System.out.println("pixelWidth:" + pixelWidth);
        System.out.println("pixelHeight:" + pixelHeight);
        System.out.println("坐标最小值:" + lowerCorner);
        System.out.println("坐标最大值:" + upperCorner);

        //遍历所有像素
        for (int i = 0; i < width; i++) {
            for (int j = 0; j < height; j++) {
                double pixelValue = image.getData().getSampleDouble(i, j, 0);

                if (pixelValue > 0.9) {
                    GridCoordinates2D gridPos = new GridCoordinates2D(i, j);
                    // 将像素点转换为坐标
                    DirectPosition worldPos = geometry.gridToWorld(gridPos);
                    double longitude = worldPos.getCoordinate()[1];
                    double latitude = worldPos.getCoordinate()[0];
                    String coordinate = "point(" + longitude + "," + latitude + ")";
                   // System.out.println(coordinate);
                    System.out.println("point[" + i + "][" + j + "]:" + pixelValue + ":" + longitude + "，" + latitude);
                }
            }
        }



    }

    public Point createPoint(double x, double y) {
        return geometryFactory.createPoint(new Coordinate(x, y));
    }

    public MultiPoint createMultiPoint(double[][] pointArrays){
        int size = pointArrays.length;
        Point[] points = new Point[size];
        for (int i = 0; i < size; i++) {
            points[i] = createPoint(pointArrays[i][0], pointArrays[i][1]);
        }
        return geometryFactory.createMultiPoint(points);
    }

    public void ReadHunanDem() {
        try {
            // DEM 文件路径
            File demFile = new File("C:/BaiduDownload/湖南省_DEM_30m分辨率_NASA数据.tif");
            // 创建 GeoTiffReader
            GeoTiffReader reader = new GeoTiffReader(demFile);
            // 读取 GridCoverage2D
            GridCoverage2D coverage = reader.read(null);
            printMetadata(coverage);
            // 关闭 reader
            reader.dispose();
        } catch (IOException | MismatchedDimensionException e) {
            e.printStackTrace();
        } catch (TransformException e) {
            e.printStackTrace();
        }
    }


    private static void printMetadata(GridCoverage2D coverage) throws TransformException {
        Envelope2D envelope2D=new Envelope2D();
        envelope2D.setCoordinateReferenceSystem(DefaultGeographicCRS.WGS84);
        envelope2D.setRect(121.00,24.00,100,100);
        // 获取坐标参考系统
        CoordinateReferenceSystem crs = coverage.getCoordinateReferenceSystem2D();
        System.out.println("Coordinate Reference System: " + crs.getName().toString());
        // 获取数据范围
        Envelope2D envelope = coverage.getEnvelope2D();
        System.out.println("Envelope: " + envelope);
        // 获取影像宽度和高度
        int width = coverage.getRenderedImage().getWidth();
        int height = coverage.getRenderedImage().getHeight();
        System.out.println("Width: " + width + ", Height: " + height);

        // 获取数据类型
        int dataType = coverage.getRenderedImage().getSampleModel().getDataType();
        System.out.println("Data Type: " + dataType);

        GridGeometry2D gridGeometry = coverage.getGridGeometry();
        System.out.println(gridGeometry);

        // 获取图斑名称
        //String[] names = coverage.getGridGeometry().getGridSetName();
        //System.out.println("Grid Set Name: " + names[0]);

        // 获取样本维度名称
        int numSampleDimensions = coverage.getNumSampleDimensions();
        String[] sampleDimensionNames = new String[numSampleDimensions];
        for (int i = 0; i < numSampleDimensions; i++) {
            sampleDimensionNames[i] = coverage.getSampleDimension(i).getDescription().toString();
        }
        System.out.println("Sample Dimension Names: " + String.join(", ", sampleDimensionNames));
    }

}
